/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package fi.uba.algo3.tp3.modelo.servicios;

import ar.uba.fi.algo3.titiritero.Posicionable;
import fi.uba.algo3.tp3.controller.UserController.Evento;
import fi.uba.algo3.tp3.modelo.actores.*;
import fi.uba.algo3.tp3.modelo.animados.PuntoTimer;
import fi.uba.algo3.tp3.modelo.contenedor.LaberintoContenedor;
import fi.uba.algo3.tp3.modelo.inanimados.Comible;
import fi.uba.algo3.tp3.modelo.inanimados.Obstaculo;
import fi.uba.algo3.tp3.modelo.servicios.exceptions.VidasNoSuficientesException;
import fi.uba.algo3.tp3.vista.Observador;
import java.util.Collection;
import java.util.LinkedList;
import ar.uba.fi.algo3.titiritero.ControladorJuego;
import fi.uba.algo3.tp3.modelo.animados.PuntoBonusTimer;
import fi.uba.algo3.tp3.modelo.inanimados.ObstaculoFijo;
import fi.uba.algo3.tp3.modelo.notificaciones.StateNotification;

/**
 *
 * @author srx
 */
public class ServicioJuego {

    public static final int TIEMPO_PODER = 1000;
    public static final long AUMENTO_PASAR_NIVEL = 5L;
    public static int contadorPuntosJugador;
    private boolean tiempoPoderOn;
    // Aqui puede hacerse contra una interfaz...
    private Pacman pacman;
    private int contadorDePuntos;
    // Por default es 3
    private int vidaJugador = 3;
    private Collection<Observador> observadores;
    private int tiempoPoder;
    private LaberintoContenedor laberinto;
    private PuntoTimer timer;
    private PuntoBonusTimer timerBonus;
    private Collection<Fantasma> fantasmas;
    private Observador vidasObserver;
    //Creo que el controlador lo debería referenciar ServicioJuego;
    private ControladorJuego controlador;

    public ServicioJuego(LaberintoContenedor laberinto) {
        this.tiempoPoderOn = Boolean.FALSE;
        this.tiempoPoder = 0;
        this.observadores = new LinkedList<Observador>();
        this.fantasmas = new LinkedList<Fantasma>();
        this.laberinto = laberinto;
        //creo que podríamos hacer que el servicio instancie al Pacman 
        //y a los fantasmas
        //this.contadorDePuntos = laberinto.getCantidadDeComibles();
        //this.pacman = new Pacman(this, 0);
//        this.pacman.setX(9);
//        this.pacman.setY(10);
        //this.controlador = new ControladorJuego();
    }

    public void iniciarServicioJuego() {
        this.contadorDePuntos = laberinto.getCantidadDeComibles();
    }

    public ControladorJuego getControlador() {
        return this.controlador;
    }

    public void aumentarPuntosJugador(int puntos) {
        contadorPuntosJugador += puntos;
    }

    public void decrementarPuntoComible() {
        contadorDePuntos--;
        if (contadorDePuntos == 0) {
            pasarJuego();
        }
    }

    public void setPoderActivado() {
        this.tiempoPoder = TIEMPO_PODER;
        timer.activar(tiempoPoder);
        this.notificarPoder();
    }

    public void setPacman(Pacman pacman) {
        this.pacman = pacman;
    }

    public void agregarObservador(Observador observer) {
        observadores.add(observer);
    }

    public boolean isTiempoPoderOn() {
        return tiempoPoderOn;
    }

    public Pacman getPacman() {
        return this.pacman;
    }

    public Comible obtenerComibleMasCercano(Posicionable posicionable, Double distancia) {
        Collection<Comible> comibles = laberinto.obtenerComibles();
        Comible comible = (Comible) detectarColisionComible(comibles, posicionable);
        // Ver si tiro o no una excepcion puede ser null
        return comible;
    }

    public Obstaculo obtenerObstaculoMasCercano(Posicionable posicionable, Double distancia) {
        Obstaculo obstaculo = (Obstaculo) detectarColisionObsctaculo(laberinto.obtenerObstaculos(), posicionable);
        return obstaculo;
    }

    private Posicionable detectarColisionComible(Collection<? extends Comible> comibles, Posicionable posicionable) {
        Personaje per = (Personaje) posicionable;
        for (Comible com : comibles) {
            if (com.hayColision(per)) {
                return com;
            }
        }
        return null;
    }

    private Posicionable detectarColisionObsctaculo(Collection<? extends Obstaculo> obstaculos, Posicionable posicionable) {
        Personaje per = (Personaje) posicionable;
        for (Obstaculo obs : obstaculos) {
            if(obs != null){
            if(obs.hayColision(per)) {
                return obs;
            }}
        }
        return null;
    }

    public void notificarPoderTerminado() {
        this.tiempoPoderOn = Boolean.FALSE;
        for (Fantasma fantasma : fantasmas) {
            fantasma.hayQueAtacar();
        }
//        for (Observador observer : observadores) {
//            observer.notificar(StateNotification.NORMAL);
//        }
    }

    public void notificarPoder() {
        this.tiempoPoderOn = Boolean.TRUE;
        for (Fantasma fantasma : fantasmas) {
            fantasma.hayQueHuir();
        }
    }

    public void setPuntoTimer(PuntoTimer timer) {
        this.timer = timer;
    }

    public void setTimerBonus(PuntoBonusTimer timerBonus) {
        this.timerBonus = timerBonus;
    }

    public int getContadorDePuntos() {
        return contadorDePuntos;
    }

    public void setVidaJugador(int vidaJugador) {
        this.vidaJugador = vidaJugador;
    }

    public void decrementarVida() throws VidasNoSuficientesException {
        if (vidaJugador == 0) {
            controlador.detenerJuego();
            throw new VidasNoSuficientesException();
        }
        this.vidasObserver.notificar(StateNotification.MUERTO);
        vidaJugador--;
        reestablecer();
    }

    private void reestablecer() {
        this.tiempoPoderOn = Boolean.FALSE;
        timerBonus.reestablecer();
        timer.reestablecer();
        pacman.reestablecer(this);
        for (Fantasma fantasma : fantasmas) {
            fantasma.reestablecer(this);
        }
    }

    public void reiniciarJuego() {
        reestablecer();
        this.contadorDePuntos = laberinto.getCantidadDeComibles();
        laberinto.reestablecerLaberinto();
    }

    public void agregarFantasmas(Fantasma fantasma) {
        this.fantasmas.add(fantasma);
    }

    public void pasarJuego() {
        long oldIntervalo = this.controlador.getIntervaloSimulacion();
        long intervalo = oldIntervalo - AUMENTO_PASAR_NIVEL;
        this.controlador.setIntervaloSimulacion((( intervalo > 0 ) ? intervalo : 0));
        reiniciarJuego();
    }

    public Integer obtenerLimiteHorizontal() {
        return laberinto.getAncho();
    }

    public Integer obtenerLimiteVertical() {
        return laberinto.getAlto();
    }

    public ObstaculoFijo obtenerJaula() {
        return laberinto.obtenerJaula();
    }

    public int getCantidadPuntos() {
        return contadorPuntosJugador;
    }

    public int getVidas() {
        return this.vidaJugador;
    }

    public void despacharEventoDeUsuario(Evento evento) {
        if (evento != null) {
            switch (evento) {
                case ABAJO:
                    pacman.cambiarSentidoAVerticalAbajo();
                    break;
                case ARRIBA:
                    pacman.cambiarSentidoAVerticalArriba();
                    break;
                case IZQUIERDA:
                    pacman.cambiarSentidoAHorizontalIzquierda();
                    break;
                case DERECHA:
                    pacman.cambiarSentidoAHorizontalDerecha();
                    break;
                default:
                    break;
            }
        }
    }

    public void setControlador(ControladorJuego controlador) {
        this.controlador = controlador;
    }

    public Integer getCantidadDeComibles() {
        return laberinto.getCantidadDeComibles();
    }

    public void bonusFueComido() {
        this.timerBonus.desabilitar();
    }

    public void setVidasObserver(Observador vidasObserver) {
        this.vidasObserver = vidasObserver;
    }

    

}
